/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "iot_cloud.h"
#include "iot_profile.h"
#include "cjson/cJSON.h"
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/**
 * @brief we make the data to a json string and send it to the iot cloud engine
 *
 */
int IotProfile_Report(int lockStatus, int pskStatus)
{
    int ret = -1;
    char *jsonString;
    IotProfileService    service;
    IotProfileKV  kvMainLockStatus;
    IotProfileKV  kvMainPskStatus;

    /* package the data */
    service.eventTime = NULL;
    service.serviceID = "SmartLock";
    service.propertyLst = &kvMainLockStatus;
    service.nxt = NULL;

    kvMainLockStatus.key = "LockAbnormal";
    kvMainLockStatus.value = &lockStatus;
    kvMainLockStatus.type = IOT_PROFILE_KEY_DATATYPE_INT;
    kvMainLockStatus.nxt = &kvMainPskStatus;

    kvMainPskStatus.key = "OriginalPsk";
    kvMainPskStatus.value = &pskStatus;
    kvMainPskStatus.type = IOT_PROFILE_KEY_DATATYPE_INT;
    kvMainPskStatus.nxt = NULL;

    jsonString = IoTProfilePackage(&service);
    if (NULL != jsonString) {
        RaiseLog(LOG_LEVEL_INFO, "jsonString:%s", jsonString);

        ret = CLOUD_ReportMsg(jsonString);
        free(jsonString);
    } else {
        RaiseLog(LOG_LEVEL_ERR, "format the report message error");
    }
    return ret;
}

int IotProfile_ReportEx(LockReportInfo *info)
{
    const char *OptionStr[OPTION_NBR] = {
        "A",
        "U",
        "D",
        "O"
    };

    const char *ResultStr[] = {
        "FAILED",
        "SUCCESS"
    };

    int ret = -1;
    char *jsonString = NULL;
    IotProfileService    service;
    IotProfileKV  kvMainLockOption;
    IotProfileKV  kvMainLockResult;

    if (info->option < OPTION_ADD || info->option >= OPTION_NBR) {
        info->option = OPTION_ADD;
    }

    if (info->result > 1) {
        info->result = 1;
    }

    /* package the data */
    service.eventTime = NULL;
    service.serviceID = "SmartLock";
    service.propertyLst = &kvMainLockOption;
    service.nxt = NULL;

    kvMainLockOption.key = "LockOption";
    kvMainLockOption.value = OptionStr[info->option];
    kvMainLockOption.type = IOT_PROFILE_KEY_DATATYPE_STRING;
    kvMainLockOption.nxt = &kvMainLockResult;

    kvMainLockResult.key = "OptionResult";
    kvMainLockResult.value = ResultStr[info->result];
    kvMainLockResult.type = IOT_PROFILE_KEY_DATATYPE_STRING;
    kvMainLockResult.nxt = NULL;

    jsonString = IoTProfilePackage(&service);
    if (NULL != jsonString) {
        RaiseLog(LOG_LEVEL_INFO, "jsonString:%s", jsonString);

        ret = CLOUD_ReportMsg(jsonString);
        free(jsonString);
    } else {
        RaiseLog(LOG_LEVEL_ERR, "format the report message error");
    }
    return ret;
}

static int GetCommandSetLock(CommandParamSetLock *setLockParam, cJSON *objCmd)
{

    cJSON *objPara = NULL;
    char *psk = NULL;
    char *pstr = NULL;

    if (setLockParam == NULL || objCmd == NULL) {
        RaiseLog(LOG_LEVEL_ERR, "NULL POINT!\n");
        return -1;
    }

    memset(setLockParam, 0x00, sizeof(CommandParamSetLock));

    if ((objPara = cJSON_GetObjectItem(objCmd, "LockStatus")) == NULL) {
        RaiseLog(LOG_LEVEL_ERR, "cJSON_GetObjectItem LampStatus failed!\n");
        return -1;
    }
    if (0 == strcmp(cJSON_GetStringValue(objPara), "ON")) {
        setLockParam->status = CN_BOARD_SWITCH_ON;
    } else {
        setLockParam->status = CN_BOARD_SWITCH_OFF;
    }

    if ((objPara = cJSON_GetObjectItem(objCmd, "Disposable")) == NULL) {
        RaiseLog(LOG_LEVEL_ERR, "cJSON_GetObjectItem LockStatus failed!\n");
        return -1;
    }
    pstr = cJSON_Print(objPara);
    if (pstr == NULL) {
        return -1;
    }
    setLockParam->isDisposable = atoi(pstr);
    free(pstr);

    if ((objPara = cJSON_GetObjectItem(objCmd, "LockPsk")) == NULL) {
        RaiseLog(LOG_LEVEL_ERR, "cJSON_GetObjectItem LockPsk failed!\n");
        return -1;
    }
    psk = cJSON_GetStringValue(objPara);
    if (psk == NULL || strlen(psk) > LOCK_PSK_LENGTH) {
        RaiseLog(LOG_LEVEL_ERR, "LockPsk is invalid!\n");
        return -1;
    }
    strncpy(setLockParam->password, psk, strlen(psk));

    RaiseLog(LOG_LEVEL_INFO, "status:%s, psk:%s (is %s)\n",
        setLockParam->status ? "ON" : "OFF",
        setLockParam->password, setLockParam->isDisposable ? "Disposable" : "not Disposable");

    return 0;
}

/**
 * @brief deal the message received from the queue
 *
 */
static int DealSetLock(cJSON *objCmd)
{

    int ret = -1;
    cJSON *objParas = NULL;
    cJSON *objPara = NULL;
    CommandParamSetLock setLockParam;

    if ((objParas = cJSON_GetObjectItem(objCmd, "paras")) == NULL) {
        RaiseLog(LOG_LEVEL_ERR, "Could not get paras in json");
        return ret;
    }

    if (GetCommandSetLock(&setLockParam, objParas) < 0) {
        RaiseLog(LOG_LEVEL_ERR, "GetCommandSetLamp failed!\n");
    }

    ret = IotProfile_CommandCallback(CLOUD_COMMAND_SETLOCK, &setLockParam);

    return ret;
}

static int DealSetPassword(cJSON *objCmd)
{
    int ret = -1;
    char *pstr = NULL;
    cJSON *objParas = NULL;
    cJSON *objPara = NULL;
    CommandParamSetPsk setLockPskParam;
    memset(&setLockPskParam, 0x00, sizeof(CommandParamSetPsk));

    if ((objParas = cJSON_GetObjectItem(objCmd, "paras")) == NULL) {
        RaiseLog(LOG_LEVEL_ERR, "Paras not exist");
        return ret;
    }

    if ((objPara = cJSON_GetObjectItem(objParas, "PskId")) != NULL) {
        char *id = cJSON_GetStringValue(objPara);
        if (id == NULL || strlen(id) > LOCK_ID_LENGTH) {
            RaiseLog(LOG_LEVEL_ERR, "check lock id failed!");
            return -1;
        }
        strncpy(setLockPskParam.id, id, strlen(id));
    } else {
        return ret;
    }

    if ((objPara = cJSON_GetObjectItem(objParas, "Option")) != NULL) {
        char *option = cJSON_GetStringValue(objPara);
        printf("option = %c \n", *option);
        if (*option == 'A') {
            setLockPskParam.option = OPTION_ADD;
        } else if (*option == 'U') {
            setLockPskParam.option = OPTION_UPDATE;
        } else if (*option == 'D') {
            setLockPskParam.option = OPTION_DELETE;
        } else {
            RaiseLog(LOG_LEVEL_ERR, "no such option(%c)!", *option);
            return -1;
        }
    } else {
        return ret;
    }

    if ((objPara = cJSON_GetObjectItem(objParas, "Disposable")) != NULL) {
        pstr = cJSON_Print(objPara);
        if (pstr == NULL) {
            return -1;
        }
        setLockPskParam.isDisposable = atoi(pstr);
        free(pstr);
        RaiseLog(LOG_LEVEL_INFO, "isDisposable(%d)!", setLockPskParam.isDisposable);
    } else {
        return ret;
    }

    if ((objPara = cJSON_GetObjectItem(objParas, "StartTime")) != NULL) {
        pstr = cJSON_Print(objPara);
        if (pstr == NULL) {
            return -1;
        }
        setLockPskParam.startTime = atoi(pstr);
        free(pstr);
    } else {
        return ret;
    }

    if ((objPara = cJSON_GetObjectItem(objParas, "EndTime")) != NULL) {
        pstr = cJSON_Print(objPara);
        if (pstr == NULL) {
            return -1;
        }
        setLockPskParam.endTime = atoi(pstr);
        free(pstr);
    } else {
        return ret;
    }
    RaiseLog(LOG_LEVEL_INFO, "startTime(%d), endTime(%d)!", setLockPskParam.startTime, setLockPskParam.endTime);
    if ((objPara = cJSON_GetObjectItem(objParas, "LockPsk")) != NULL) {
        char *psk = cJSON_GetStringValue(objPara);
        if (psk == NULL || strlen(psk) > LOCK_PSK_LENGTH) {
            RaiseLog(LOG_LEVEL_ERR, "check psk failed!");
            return -1;
        }
        strncpy(setLockPskParam.password, psk, strlen(psk));
    } else {
        return ret;
    }

    ret = IotProfile_CommandCallback(CLOUD_COMMAND_SETPSK, &setLockPskParam);

    return ret;
}

int CLOUD_CommandCallBack(const char *jsonString)
{
    cJSON *objRoot = NULL;
    cJSON *objCmdName = NULL;
    int ret = -1;
    if (jsonString == NULL) {
        return ret;
    }

    if ((objRoot = cJSON_Parse(jsonString)) == NULL) {
        RaiseLog(LOG_LEVEL_ERR, "could not parse the payload\r\n");
        goto EXIT_JSONPARSE;
    }

    if ((objCmdName = cJSON_GetObjectItem(objRoot, "command_name")) == NULL) {
        RaiseLog(LOG_LEVEL_ERR, "%s:could not get the cmd name from json\r\n");
        goto EXIT_CMDOBJ;
    }

    if (0 == strcmp(cJSON_GetStringValue(objCmdName), "SetLockStatus")) {
        ret = DealSetLock(objRoot);
    } else if (0 == strcmp(cJSON_GetStringValue(objCmdName), "SetLockPsk")) {
        ret = DealSetPassword(objRoot);
    } else {
        RaiseLog(LOG_LEVEL_ERR, "unresolved command:%d\r\n", cJSON_GetStringValue(objCmdName));
    }

EXIT_CMDOBJ:
EXIT_JSONPARSE:
    if (objRoot != NULL) {
        cJSON_Delete(objRoot);
    }
    return ret;

}




